home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2005 March / Macworld CD March 2005 - Marathon Trilogy.iso / Shareware World / iPod / iPodderX.sit / iPodderX / iPodderX.app / Contents / Resources / zurllib.py < prev    next >
Encoding:
Python Source  |  2005-01-07  |  4.2 KB  |  148 lines

  1. #
  2. # zurllib.py
  3. #
  4. # This is (hopefully) a drop-in for urllib which will request gzip/deflate
  5. # compression and then decompress the output if a compressed response is
  6. # received while maintaining the API.
  7. #
  8. # by Robert Stone 2/22/2003 
  9. #
  10.  
  11. from urllib import *
  12. from urllib2 import *
  13. from gzip import GzipFile
  14. from StringIO import StringIO
  15. from __init__ import version
  16. import pprint
  17.  
  18.  
  19. DEBUG=0
  20.  
  21.  
  22. class HTTPContentEncodingHandler(HTTPHandler):
  23.     """Inherit and add gzip/deflate/etc support to HTTP gets."""
  24.     def http_open(self, req):
  25.         # add the Accept-Encoding header to the request
  26.         # support gzip encoding (identity is assumed)
  27.         req.add_header("Accept-Encoding","gzip")
  28.         req.add_header('User-Agent', 'BitTorrent/' + version)
  29.         if DEBUG: 
  30.             print "Sending:" 
  31.             print req.headers
  32.             print "\n"
  33.         fp = HTTPHandler.http_open(self,req)
  34.         headers = fp.headers
  35.         if DEBUG: 
  36.              pprint.pprint(headers.dict)
  37.         url = fp.url
  38.         return addinfourldecompress(fp, headers, url)
  39.  
  40.  
  41. class addinfourldecompress(addinfourl):
  42.     """Do gzip decompression if necessary. Do addinfourl stuff too."""
  43.     def __init__(self, fp, headers, url):
  44.         # we need to do something more sophisticated here to deal with
  45.         # multiple values?  What about other weird crap like q-values?
  46.         # basically this only works for the most simplistic case and will
  47.         # break in some other cases, but for now we only care about making
  48.         # this work with the BT tracker so....
  49.         if headers.has_key('content-encoding') and headers['content-encoding'] == 'gzip':
  50.             if DEBUG:
  51.                 print "Contents of Content-encoding: " + headers['Content-encoding'] + "\n"
  52.             self.gzip = 1
  53.             self.rawfp = fp
  54.             fp = GzipStream(fp)
  55.         else:
  56.             self.gzip = 0
  57.         return addinfourl.__init__(self, fp, headers, url)
  58.  
  59.     def close(self):
  60.         self.fp.close()
  61.         if self.gzip:
  62.             self.rawfp.close()
  63.  
  64.     def iscompressed(self):
  65.         return self.gzip
  66.  
  67. class GzipStream(StringIO):
  68.     """Magically decompress a file object.
  69.  
  70.        This is not the most efficient way to do this but GzipFile() wants
  71.        to seek, etc, which won't work for a stream such as that from a socket.
  72.        So we copy the whole shebang info a StringIO object, decompress that
  73.        then let people access the decompressed output as a StringIO object.
  74.  
  75.        The disadvantage is memory use and the advantage is random access.
  76.  
  77.        Will mess with fixing this later.
  78.     """
  79.  
  80.     def __init__(self,fp):
  81.         self.fp = fp
  82.  
  83.         # this is nasty and needs to be fixed at some point
  84.         # copy everything into a StringIO (compressed)
  85.         compressed = StringIO()
  86.         r = fp.read()
  87.         while r:
  88.             compressed.write(r)
  89.             r = fp.read()
  90.         # now, unzip (gz) the StringIO to a string
  91.         compressed.seek(0,0)
  92.         gz = GzipFile(fileobj = compressed)
  93.         str = ''
  94.         r = gz.read()
  95.         while r:
  96.             str += r
  97.             r = gz.read()
  98.         # close our utility files
  99.         compressed.close()
  100.         gz.close()
  101.         # init our stringio selves with the string 
  102.         StringIO.__init__(self, str)
  103.         del str
  104.  
  105.     def close(self):
  106.         self.fp.close()
  107.         return StringIO.close(self)
  108.  
  109.  
  110. def test():
  111.     """Test this module.
  112.  
  113.        At the moment this is lame.
  114.     """
  115.  
  116.     print "Running unit tests.\n"
  117.  
  118.     def printcomp(fp):
  119.         try:
  120.             if fp.iscompressed():
  121.                 print "GET was compressed.\n"
  122.             else:
  123.                 print "GET was uncompressed.\n"
  124.         except:
  125.             print "no iscompressed function!  this shouldn't happen"
  126.  
  127.     print "Trying to GET a compressed document...\n"
  128.     fp = urlopen('http://a.scarywater.net/hng/index.shtml')
  129.     print fp.read()
  130.     printcomp(fp)
  131.     fp.close()
  132.  
  133.     print "Trying to GET an unknown document...\n"
  134.     fp = urlopen('http://www.otaku.org/')
  135.     print fp.read()
  136.     printcomp(fp)
  137.     fp.close()
  138.  
  139.  
  140. #
  141. # Install the HTTPContentEncodingHandler that we've defined above.
  142. #
  143. install_opener(build_opener(HTTPContentEncodingHandler))
  144.  
  145. if __name__ == '__main__':
  146.     test()
  147.  
  148.